using System;
using System.Text;
using System.Xml;

namespace Slaks.DocumentSerialization.TermIdInfo
{
	/*
	 *  <term_id_info>
	 *    <total>2</total>
	 *    <entry term="slaks" id="2" frequency="12"/>
	 *    <entry term="kuki" id=3 frequency="21"/>
	 *  </term_id_info>
	 */

	public class TermIdInfo
	{
		private TermIdInfoMap m_termIdDictionary;

		public TermIdInfo()
		{
		}

		public TermIdInfoMap TermIdDictionary
		{
			get { return m_termIdDictionary; }
			set { m_termIdDictionary = value; }
		}

		public void XmlWrite(string path)
		{
			XmlTextWriter writer = null;

			TermIdInfoList list = new TermIdInfoList();
			foreach (TermIdInfoElement termIdInfoElement in m_termIdDictionary.Values)
			{
				list.Add(termIdInfoElement);
			}

			list.Sort();

			try
			{
				writer = new XmlTextWriter(path, Encoding.UTF8);
				writer.Formatting = Formatting.Indented;
				writer.WriteStartDocument();

				writer.WriteStartElement(Grammar.TermIdInfo.TermIdInfoElement);

				writer.WriteElementString(Grammar.TermIdInfo.TotalElement, m_termIdDictionary.Count.ToString());


				foreach (TermIdInfoElement termIdInfoElement in list)
				{
					writer.WriteStartElement(Grammar.TermIdInfo.EntryElement);
					writer.WriteStartAttribute(Grammar.TermIdInfo.TermAttr, "");
					writer.WriteString(termIdInfoElement.Term);
					writer.WriteEndAttribute();

					writer.WriteStartAttribute(Grammar.TermIdInfo.IdAttr, "");
					writer.WriteString(termIdInfoElement.Id.ToString());
					writer.WriteEndAttribute();

					writer.WriteStartAttribute(Grammar.TermIdInfo.FrequencyAttr, "");
					writer.WriteString(termIdInfoElement.Frequency.ToString());
					writer.WriteEndAttribute();

					writer.WriteEndElement();
				}

				writer.WriteEndElement();
				writer.WriteEndDocument();
			}
			catch (Exception ex)
			{
				throw ex;
			}
			finally
			{
				writer.Close();
			}
		}

		/// <summary>
		/// Read the term_id_info.xml file int TermIdInfoMap (key = term, value = TermIdInfoElement)
		/// </summary>
		/// <param name="filename"></param>
		/// <returns></returns>
		public static TermIdInfoMap ReadXml(string filename)
		{
			TermIdInfoMap map = new TermIdInfoMap();

			XmlReader reader = null;
			try
			{
				reader = new XmlTextReader(filename);
				long index = 0;

				long total = SkipTotal(reader);
				if (total < 0) return null;

				TermIdInfoElement element;
				while (index < total)
				{
					element = ReadTermIdInfo(reader);
					if (element == null) break;
					map.Add(element.Term,element);
					++index;
				}
			}
			catch (Exception ex)
			{
				throw ex;
			}
			finally
			{
				if (reader != null) reader.Close();
			}

			return map;
		}


		/// <summary>
		/// Read the term_id_info.xml file int TermIdInfoList (value = TermIdInfoElement)
		/// </summary>
		/// <param name="filename">path to the term_id_info.xml file</param>
		/// <param name="count">number of records to read, 0 stands for all-records</param>
		/// <returns></returns>
		public static TermIdInfoList ReadXml(string filename, long count)
		{
			TermIdInfoList list = new TermIdInfoList();

			XmlReader reader = null;
			try
			{
				reader = new XmlTextReader(filename);
				long index = 0;

				long total = SkipTotal(reader);
				if (total < 0) return null;

				if (count <= 0) count = total;

				TermIdInfoElement element;
				while (index < count)
				{
					element = ReadTermIdInfo(reader);
					if (element == null) break;
					list.Add(element);
					++index;
				}
			}
			catch (Exception ex)
			{
				throw ex;
			}
			finally
			{
				if (reader != null) reader.Close();
			}

			return list;
		}

		private static long SkipTotal(XmlReader reader)
		{
			while (reader.Read())
			{
				if (reader.NodeType != XmlNodeType.Element) continue;
				if (string.Equals(Grammar.TermIdInfo.TotalElement, reader.Name))
				{
					return long.Parse(reader.ReadElementString(reader.Name));
				}
			}
			return -1;
		}

		private static TermIdInfoElement ReadTermIdInfo(XmlReader reader)
		{
			string term;
			long id;
			int frequency;
			while (reader.Read())
			{
				if (reader.NodeType != XmlNodeType.Element) continue;
				if (string.Equals(Grammar.TermIdInfo.EntryElement, reader.Name))
				{
					reader.MoveToAttribute(Grammar.TermIdInfo.TermAttr);
					reader.ReadAttributeValue();
					term = reader.Value;
					reader.MoveToAttribute(Grammar.TermIdInfo.IdAttr);
					id = long.Parse(reader.Value);
					reader.MoveToNextAttribute();
					frequency = int.Parse(reader.Value);
					TermIdInfoElement element = new TermIdInfoElement(term, id, frequency);
					return element;
				}
			}
			return null;
		}
	}
}